# -*- coding: utf-8 -*-
__author__ = 'lztkdr'
__date__ = '2020/4/7 10:11'
"""

朝阳医院2018年销售数据 分析


# https://www.jianshu.com/p/4f17fda2eacf
# 链接:https://pan.baidu.com/s/1NFCMP8QbIsMCgDrXEq5GCw 密码:o558

"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Pycharm输出窗口有省略号，数据显示不全解决方法
pd.set_option('display.max_rows', 10)
pd.set_option('display.max_columns', 200)
pd.set_option('display.width', 1000)

"""
防止出现：
FutureWarning: Using an implicitly registered datetime converter for a matplotlib plotting method. The converter was registered by pandas on import. Future versions of pandas will require you to explicitly register matplotlib converters.
"""
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()

# 如果要显示中文标题和坐标表示，需要添加以下两行代码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

print('============================================================================================================')

file = './朝阳医院2018年销售数据.xlsx'

# xls = pd.ExcelFile(file)
# df = xls.parse('Sheet1', dtype='object')

df = pd.read_excel(file, 'Sheet1', dtype='object')

print(df.info())
print('============================================================================================================')
print(df.columns)
print('==========================================')
print(df.index)
print('==========================================')
print(df.head(3))
print('==========================================')
# 列名重命名
# inplace 为 True 则 不需要返回值，就改变 df 中的数据
df.rename(columns={'购药时间': '销售时间'}, inplace=True)
# 不使用 inplace 则使用返回值来 改变 df 中的数据
df = df.rename(columns={'购药时间': '销售时间'})
print(df.head(3))
print('==========================================')
print(df.count())
print('==========================================')
# 数据类型转换
print(df.dtypes)
print('==========================================')
df['销售数量'] = df['销售数量'].astype(float)
df['应收金额'] = df['应收金额'].astype(float)
df['实收金额'] = df['实收金额'].astype(float)
print(df.dtypes)
print('==========================================')


# 在“销售时间”这一列数据中存在星期这样的数据，但在数据分析过程中不需要用到，因此要把销售时间 的 星期 去掉
# 提取日期部分

def splitTime(times):
	import re
	lst = []
	for time in times:
		# 判断变量 是否是 null 值
		if pd.notnull(time):
			try:
				s = re.search('(\d{4}-\d{2}-\d{2}).+', str(time).strip()).group(1)
				lst.append(s)
			except Exception as e:
				print(e)
		else:
			lst.append(time)
	return lst


"""
 pandas 批量赋值时 一定注意 !!! 索引必须相对应，特别是当 dropna 之后 导致索引变更，又进行赋值
 会发现 数据赋值不对应， 用 df.tail(n) 可以尝试发现问题。
"""

# 将所有 销售时间 提取出来
df['销售时间'] = splitTime(df.loc[:, '销售时间'])
print("提取销售日期head：\n", df.head(5))
print('==========================================')
print('提取销售日期tail:\n', df.tail(5))
print('==========================================')
print('提取销售日期sample:\n', df.sample(5))
print('==========================================')
# 将日期部分转为日期时间类型
df['销售时间'] = pd.to_datetime(df['销售时间'], format='%Y-%m-%d', errors='coerce')
print(df.dtypes)
print('============================================================================================================')
"""
 不要轻易 dropna ， 发现 dropna之后，
 再去 进行 
    将日期部分转为日期时间类型（df['销售时间'] = pd.to_datetime ...），
    将所有 销售时间 提取出来 （df['销售时间'] = splitTime ...）
 索引对应不住，赋值错位，会有严重问题！！！

  出现这个情况，要么重新 给df 赋值 连续的 索引数组，
  要么 在进行赋值的时候，应该是 Series 数组类型，并且索引 和 df 的要一致！！！
"""
# 缺失数据处理
df.dropna(subset=['销售时间', '社保卡号'], how='any', inplace=True)
# 不使用 inplace 则使用返回值来 改变 df 中的数据
df = df.dropna(subset=['销售时间', '社保卡号'], how='any')
print(df.count())

# 一般在 dropna 后，可能需要重建索引。
# drop=True 使用drop参数来避免将旧索引添加为列
# inplace=True 执行后 直接生效
df.reset_index(drop=True, inplace=True)

print("dropna head：\n", df.head(5))
print('==========================================')
print('dropna tail:\n', df.tail(5))
print('==========================================')

# 数据排序
df = df.sort_values(by='销售时间', ascending=True)
print("sort_values head：\n", df.head(5))
print('==========================================')
print("sort_values tail：\n", df.tail(5))
print('============================================================================================================')
# 异常值处理
# describe() 可以展示所有的 float 类型的列的 统计计数
print(df.describe())
"""
	通过描述统计信息可以看到，“销售数量”、“应收金额”、“实收金额”这三列数据的最小值出现了负数，
这明显不符合常理，数据中存在异常值的干扰，因此要对数据进一步处理，以排除异常值的影响

"""
df = df[df.销售数量 > 0]

print(df.describe())

print('==========================================')

# 删除 相同时间和相同社保  重复数据
df.drop_duplicates(subset=['销售时间', '社保卡号'], keep=False, inplace=True)
print('消费次数：', df.shape)
print("drop_duplicates tail：\n", df.head(3))
print('==========================================')
print("drop_duplicates tail：\n", df.tail(3))
# 去重之后，重建索引
print(df.reset_index(drop=True, inplace=True))
print('==========================================')

# 每天销售数量 排名前10
grouped = df.groupby(by='销售时间').count()['序号']

# <class 'pandas.core.series.Series'>
print(type(grouped))

xy = grouped.sort_values(ascending=False)[:10]
print(xy)

x = list(" " + j for j in xy.index.astype(str))
y = list(xy.values)

plt.cla()
plt.figure(figsize=(20, 8), dpi=80)
plt.bar(x, y, width=0.2, color='orange')
plt.grid()
plt.show()
print('==========================================')

# 数据总行数
total = df.shape[0]
print('总消费次数：', total)

df = df.sort_values(by='销售时间', ascending=True)
print(type(df))
print(df.head(10))
print('==========================================')
# 最小日期值
begin_date = df.loc[0, '销售时间']
# 最大日期值
end_date = df.loc[total - 1, '销售时间']
print('begin_date:', begin_date, '\nend_date:', end_date)

# 相隔天数
days = (end_date - begin_date).days
print('days:', days)

# 月数
months = days // 30
print('months:', months)

# 月平均消费次数
kpi1 = total // months
print('月平均消费次数 :', kpi1)

kpi2 = df['实收金额'].sum() // months
print('月平均消费金额 :', kpi2)

kpi3 = df['实收金额'].sum() // total
print('平均单次消费金额 :', kpi3)
print('==========================================')

plt.cla()
plt.figure(figsize=(20, 8), dpi=80)
df2 = df.copy()
df2.index = df.销售时间
# 画 折线图
plt.plot(df2.实收金额)
plt.title('每天消费金额图')
plt.xlabel("时间")
plt.ylabel("金额")
plt.grid()
plt.show()


print('==========================================')

# 按天统计 实收金额
df2 = df.groupby(by=['销售时间']).sum()['实收金额']
print(type(df2))
print('按天统计实收金额：\n', df2)
print('===========================')
# 按月统计 实收金额
df3 = df2.groupby(by=df2.index.month).sum()
print(type(df3))
print('按月统计实收金额：\n', df3)

plt.cla()
plt.figure(figsize=(20, 8), dpi=80)
# 画折线图
plt.plot(df3)
plt.title('每月实收金额图')
plt.xlabel("月份")
plt.ylabel("实收金额")
plt.grid()
plt.show()

"""
	结果显示，7月消费金额最少，这是因为7月份的数据不完整，所以不具参考价值。
1月、4月、5月和6月的月消费金额差异不大，2月和3月的消费金额迅速降低，这可能是2月和3月处于春节期间，大部分人都回家过年的原因。

"""

print('==========================================')
print(df[['商品名称', '销售数量']])
# print(df['商品名称','销售数量']) # 不能直接同时 输入多个列名，多个列名需要再用中括号
print('==========================================')
df2 = df[['商品名称', '销售数量']].groupby(by='商品名称')['销售数量'].sum()
xy = df2.sort_values(ascending=False)[:10]

print(xy)

plt.cla()
plt.figure(figsize=(20, 8), dpi=80)
plt.bar(xy.index, xy.values, width=0.2, color='orange')
plt.xticks(xy.index, rotation=45)
plt.title('商品销售统计')
plt.xlabel("商品名称")
plt.ylabel("销售数量")
plt.grid()
plt.show()

print('==========================================')
